#ifndef PICCOLO_LOG_H
#define PICCOLO_LOG_H

#include "PiccoloEngine.h"

#include "spdlog/common.h"

namespace Piccolo
{
    class PiccoloLog
    {
    public:
        PiccoloLog() = delete;
        PiccoloLog(const PiccoloLog&) = delete;
        PiccoloLog &operator=(const PiccoloLog&) = delete;

        static void Init();

        static PiccoloLog* GetLoggerInstance()
        {
            return &sLoggerInstance;
        }

        template<typename... Args>
        void Log(spdlog::source_loc loc, spdlog::level::level_enum lvl, spdlog::format_string_t<Args...> fmt, Args&& ...args)
        {
            spdlog::memory_buf_t buf;
            fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(args...));
            Log(loc, lvl, buf);
        }

    private:
        void Log(spdlog::source_loc loc, spdlog::level::level_enum lvl, const spdlog::memory_buf_t& buffer);

        static PiccoloLog sLoggerInstance;
    };

#define PICCOLO_LOG_LOGGER_CALL(log, level, ...) \
    (log)->Log(spdlog::source_loc{ __FILE__, __LINE__, SPDLOG_FUNCTION }, level, __VA_ARGS__)

#define LOG_T(...) PICCOLO_LOG_LOGGER_CALL(Piccolo::PiccoloLog::GetLoggerInstance(), spdlog::level::trace, __VA_ARGS__)
#define LOG_D(...) PICCOLO_LOG_LOGGER_CALL(Piccolo::PiccoloLog::GetLoggerInstance(), spdlog::level::debug, __VA_ARGS__)
#define LOG_I(...) PICCOLO_LOG_LOGGER_CALL(Piccolo::PiccoloLog::GetLoggerInstance(), spdlog::level::info, __VA_ARGS__)
#define LOG_W(...) PICCOLO_LOG_LOGGER_CALL(Piccolo::PiccoloLog::GetLoggerInstance(), spdlog::level::warn, __VA_ARGS__)
#define LOG_E(...) PICCOLO_LOG_LOGGER_CALL(Piccolo::PiccoloLog::GetLoggerInstance(), spdlog::level::err, __VA_ARGS__)
}

#endif